package console;

import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JTextArea;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

import cli.CmdExcecuter;


public class JConsole extends JTextArea implements KeyListener
{
	private static final long serialVersionUID	= -5866169869353990380L;
	private CommandHistory history;
	int editStart;
	boolean	running;
	private ConsoleFilter filter;
	private Thread serviceThread;
	public JConsole()
	{
		
		history = new CommandHistory();
		setTabSize(4);		
		addKeyListener(this);
		filter = new ConsoleFilter(this);
		((AbstractDocument) getDocument()).setDocumentFilter(filter);
		
		setText("***** CAOS PROJEKT | Carletti *****\r\n.help for command list\r\n>>> ");
		
		getCaret().setDot(editStart);
		setBackground(Color.BLACK);
		setForeground(Color.GREEN);
	}

	@Override
	public void setText(String text)
	{
		setText(text, true);
	}

	/**
	 * @param text
	 * @param updateEditStart
	 */
	public void setText(String text, boolean updateEditStart)
	{
		filter.useFilters = false;
		super.setText(text);
		filter.useFilters = true;
		if (updateEditStart)
		{
			editStart = text.length();
		}
		getCaret().setDot(text.length());
	}

	private class ConsoleFilter extends DocumentFilter
	{
		private JConsole	console;
		public boolean		useFilters;

		public ConsoleFilter(JConsole console)
		{
			this.console = console;
			useFilters = true;
		}

		@Override
		public void insertString(DocumentFilter.FilterBypass fb, int offset, String string, AttributeSet attr)
				throws BadLocationException
		{
			if (useFilters)
			{
				
				if (console.getSelectionStart() >= console.editStart)
				{
					
					fb.insertString(offset, string, attr);
				}
				else
				{
					
					fb.insertString(console.getText().length(), string, attr);
					
					console.getCaret().setDot(console.getText().length());
				}
			}
			else
			{
				fb.insertString(offset, string, attr);
			}
		}

		@Override
		public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
				throws BadLocationException
		{
			if (useFilters)
			{
				
				if (console.getSelectionStart() >= console.editStart)
				{
					
					fb.replace(offset, length, text, attrs);
				}
				else
				{
					
					fb.insertString(console.getText().length(), text, attrs);
					
					console.getCaret().setDot(console.getText().length());
				}
			}
			else
			{
				fb.replace(offset, length, text, attrs);
			}
		}

		@Override
		public void remove(DocumentFilter.FilterBypass fb, int offset, int length) throws BadLocationException
		{
			if (useFilters)
			{
				if (offset > console.editStart)
				{
					
					fb.remove(offset, length);
				}
				else
				{
					
					fb.remove(console.editStart, length - (console.editStart - offset));
					
					console.getCaret().setDot(console.editStart);
				}
			}
			else
			{
				fb.remove(offset, length);
			}
		}
	}

	@Override
	public void keyPressed(KeyEvent e)
	{
		if (e.isControlDown())
		{
			if (e.getKeyCode() == KeyEvent.VK_A && !e.isShiftDown() && !e.isAltDown())
			{
				if (getSelectionStart() >= editStart)
				{
					if (getSelectionStart() != editStart || getSelectionEnd() != this.getText().length())
					{
						setSelectionStart(editStart);
						setSelectionEnd(this.getText().length());
						
						e.consume();
					}
				}
			}
			else if (e.getKeyCode() == KeyEvent.VK_DOWN && !e.isShiftDown() && !e.isAltDown())
			{
				
				StringBuilder temp = new StringBuilder(getText());
			
				temp.delete(editStart, temp.length());
				temp.append(history.getNextCommand());
				setText(temp.toString(), false);
				e.consume();
			}
			else if (e.getKeyCode() == KeyEvent.VK_UP && !e.isShiftDown() && !e.isAltDown())
			{
				
				StringBuilder temp = new StringBuilder(getText());
				
				temp.delete(editStart, temp.length());
				temp.append(history.getPrevCommand());
				setText(temp.toString(), false);
				e.consume();
			}
		}
		else if (e.getKeyCode() == KeyEvent.VK_ENTER)
		{
			
			if (!e.isShiftDown() && !e.isAltDown())
			{
				if (running)
				{
					
				}
				else
				{
					StringBuilder text = new StringBuilder(this.getText());
					String command = text.substring(editStart);
					text.append(System.getProperty("line.separator"));
					setText(text.toString());
					history.add(command);
					serviceThread = new Thread(new Runner(command));
					serviceThread.setDaemon(true);
					serviceThread.start();
				}
				e.consume();
			}
			else if (!e.isAltDown())
			{
				
				StringBuilder text = new StringBuilder(this.getText());
				if (getSelectedText() != null)
				{
				
					text.delete(getSelectionStart(), getSelectionEnd());
				}
				text.insert(getSelectionStart(), System.getProperty("line.separator"));
				setText(text.toString(), false);
			}
		}
		else if (e.getKeyCode() == KeyEvent.VK_HOME)
		{
			int selectStart = getSelectionStart();
			if (selectStart > editStart)
			{
				
				for (int i = editStart; i < selectStart; i++)
				{
					if (this.getText().charAt(i) == '\n')
					{
						
						return;
					}
				}
				if (e.isShiftDown())
				{
			
					getCaret().moveDot(editStart);
				}
				else
				{

					getCaret().setDot(editStart);
				}
				e.consume();
			}
		}
	}
	private class Runner implements Runnable
	{
		private String	commands;

		public Runner(String commands)
		{
			this.commands = commands;
		}

		@Override
		public void run()
		{
			running = true;	
			CmdExcecuter.execute(JConsole.this, commands);
			StringBuilder text = new StringBuilder(getText());
			text.append(">>> ");
			setText(text.toString());
			setCaretPosition(getDocument().getLength());
			running = false;
		}
	}

	@Override
	public void keyReleased(KeyEvent e)
	{
	}

	@Override
	public void keyTyped(KeyEvent e)
	{
	}
}
